home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / utils / console / splitvt-.000 / splitvt- / splitvt-1.6.1 / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-09  |  14.5 KB  |  777 lines

  1. /* Miscellaneous system dependent routines for splitsh */
  2.  
  3. #include    <sys/types.h>
  4. #include    <sys/stat.h>
  5. #include    <fcntl.h>
  6. #include    <stdio.h>
  7. #include    <signal.h>
  8.  
  9.  
  10. #ifdef HAVE_TERMIO_H
  11. #include    <termio.h>
  12. #else
  13. #include    <sys/ioctl.h>
  14. #endif  /* HAVE_TERMIO_H */
  15.  
  16. #ifdef HAVE_BSDTTY_H
  17. #include    <sys/bsdtty.h>
  18. #ifndef TIOCNOTTY
  19. #define TIOCNOTTY    _IO('t', 113)    /* HP-UX void tty definition */
  20. #endif
  21. #endif /* HAVE_BSDTTY_H */
  22.  
  23. #ifdef NEED_INET_H
  24. /*#define STTY_HACK*/
  25. #endif
  26.  
  27. /*
  28.  * Initialize a pty, fork a command running under it, and then 
  29.  * return the master file descriptor
  30.  */
  31.  
  32. extern int WU_lines, WL_lines, W_columns;    /* From vt100.c */
  33.  
  34. #define UPPER    0        /* Upper window definition */
  35. #define LOWER    1        /* Lower window definition */
  36.  
  37. int pty_open(argv, childpid, win)
  38. char *argv[];
  39. int *childpid;
  40. int win;        /* 0 for upper, 1 for lower */
  41. {
  42.  
  43.     void dropctty(), pty_setwin();
  44.     int get_master_pty(), get_slave_pty();
  45.     char *get_ttyname(), *myputenv();
  46.  
  47.     char LINES[12], COLUMNS[12], SPLITVT[24];
  48.     int returnfd, slave_fd;
  49.  
  50.     /* Get the master pty file descriptor */
  51.     if ( (returnfd=get_master_pty()) < 0 )
  52.         return(-1);
  53.  
  54.     /* Fork and go! */
  55.     if ( ((*childpid)=fork()) < 0 )
  56.         return(-1);
  57.     else if ( (*childpid) == 0 )
  58.     {
  59.         dropctty();    /* Lose controlling tty */
  60.  
  61.         if ( (slave_fd=get_slave_pty()) < 0 )
  62.         {
  63.             perror("Can't open slave tty");
  64.             exit(128);
  65.         }
  66.         close(0); close(1); close(2);
  67.         dup(slave_fd); dup(slave_fd); dup(slave_fd);
  68.         close(slave_fd); close(returnfd);
  69.  
  70.         /* Reattatch the new tty as the controlling terminal */
  71.         /* Under old UNIX, just opening the new tty after
  72.            losing the controlling tty is good enough.
  73.            Under newer Unices, it requires an ioctl().  */
  74. #ifdef TIOCSCTTY
  75.         (void) ioctl(0, TIOCSCTTY, 0);
  76. #endif
  77.  
  78.         /* Set the lines and columns on the new tty */
  79. #ifdef TIOCGWINSZ    /* We don't want to set the environment if possible */
  80.         pty_setwin(0, win);
  81. #else
  82.         if ( win == UPPER )
  83.             sprintf(LINES, "LINES=%d", WU_lines);
  84.         else
  85.             sprintf(LINES, "LINES=%d", WL_lines);
  86.         myputenv(LINES);
  87.         sprintf(COLUMNS, "COLUMNS=%d", W_columns);
  88.         myputenv(COLUMNS);
  89. #endif /* TIOCGWINSZ */
  90.         /* Set the SPLITVT environment variable for shell scripts */
  91.         if ( win == UPPER )
  92.             sprintf(SPLITVT, "SPLITVT=upper");
  93.         else
  94.             sprintf(SPLITVT, "SPLITVT=lower");
  95.         myputenv(SPLITVT);
  96.         myputenv("TERM=vt100");    /* Put the new TERM in the env. */
  97.  
  98. #ifdef SIGTSTP
  99.         signal(SIGTSTP, SIG_IGN);
  100. #endif
  101. #ifdef STTY_HACK
  102.         system("stty sane echo echoe intr '^C' erase '^H'");
  103. #else
  104.         (void) tty_reset(0);
  105. #endif
  106.         /* "touch" the tty so 'w' reports proper idle times */
  107.         (void) utime(get_ttyname(), NULL);
  108.  
  109.         /* Set our uid to our real uid if necessary */
  110.         (void) setuid(getuid());
  111.             
  112.         /* Run the requested program, with possible leading dash. */
  113.         execvp(((*argv[0] == '-') ? argv[0]+1 : argv[0]), argv);
  114.         perror(argv[0]);
  115.         exit(255);
  116.     }
  117.     return(returnfd);
  118. }
  119.  
  120.  
  121.  
  122. /*
  123.  * Pseudo-terminal routines for Unix System V Release 3.2 and BSD4.2-3
  124.  */
  125.  
  126.  
  127. extern int errno;
  128. int master_fd;
  129.  
  130. char tty_name[64]={'\0'};
  131. char pty_name[64]={'\0'};
  132.  
  133. char *get_ttyname()
  134. {
  135.     if ( tty_name[0] )
  136.         return(tty_name);
  137.     return(NULL);
  138. }
  139.  
  140. #ifdef IRIX    /* IRIX System V for SGI machines */
  141.  
  142. extern char *_getpty();
  143.  
  144. int get_master_pty()
  145. {
  146.  
  147.     char     *ttyptr;
  148.  
  149.     if ( (ttyptr=_getpty(&master_fd, O_RDWR, 0600, 0)) == 0 )
  150.         return(-1);
  151.     else
  152.         strcpy(tty_name, ttyptr);
  153.  
  154.     return(master_fd);
  155. }
  156.  
  157. /*
  158.  * Open the slave half of a pseudo-terminal.
  159.  */
  160.  
  161. int get_slave_pty()
  162. {
  163.     int    slave_fd;
  164.     char    *slavename;
  165.  
  166.     slavename=tty_name;
  167.  
  168.     if (slavename == NULL) {
  169.         close(master_fd);
  170.         return(-1);
  171.     }
  172.  
  173.     if ( (slave_fd=open(slavename, O_RDWR)) < 0 )    /* open the slave */
  174.     {
  175.         close(master_fd);
  176.         return(-1);
  177.     }
  178.  
  179.     return(slave_fd);
  180. }
  181. #else /* ! IRIX */
  182.  
  183.  
  184. #ifdef SOLARIS        /* System V.4 pty routines from W. Richard Stevens */
  185.  
  186. #include <stropts.h>
  187.  
  188. #define DEV_CLONE    "/dev/ptmx"
  189.  
  190. extern char *ptsname();
  191.  
  192. int get_master_pty()
  193. {
  194.  
  195.     char     *ttyptr;
  196.  
  197.     if ( (master_fd=open(DEV_CLONE, O_RDWR)) < 0 )
  198.         return(-1);
  199.  
  200.     if ( grantpt(master_fd) < 0 )    /* grant access to slave */
  201.     {
  202.         close(master_fd);
  203. #ifdef DEBUG
  204.         perror("grantpt()");
  205. #endif
  206.         return(-1);
  207.     }
  208.  
  209.     if ( unlockpt(master_fd) < 0 )    /* clear slave's lock flag */
  210.     {
  211.         close(master_fd);
  212.         return(-1);
  213.     }
  214.  
  215.     if ( (ttyptr=ptsname(master_fd)) == NULL )
  216.     {
  217.         close(master_fd);
  218.         return(-1);
  219.     }
  220.     else
  221.         strcpy(tty_name, ttyptr);
  222.  
  223.     return(master_fd);
  224. }
  225.  
  226. /*
  227.  * Open the slave half of a pseudo-terminal.
  228.  */
  229.  
  230. int get_slave_pty()
  231. {
  232.     int    slave_fd;
  233.     char    *slavename;
  234.  
  235.     slavename=tty_name;
  236.  
  237.     if ( (slave_fd=open(slavename, O_RDWR)) < 0 )    /* open the slave */
  238.     {
  239.         close(master_fd);
  240.         return(-1);
  241.     }
  242.  
  243.     if ( ioctl(slave_fd, I_PUSH, "ptem") < 0 )
  244.     {
  245.         close(master_fd);
  246.         close(slave_fd);
  247.         return(-1);
  248.     }
  249.  
  250.     if ( ioctl(slave_fd, I_PUSH, "ldterm") < 0 )
  251.     {
  252.         close(master_fd);
  253.         close(slave_fd);
  254.         return(-1);
  255.     }
  256.  
  257.     if ( ioctl(slave_fd, I_PUSH, "ttcompat") < 0 )
  258.     {
  259.         close(master_fd);
  260.         close(slave_fd);
  261.         return(-1);
  262.     }
  263.  
  264.     return(slave_fd);
  265. }
  266.  
  267. #else    /* BSD, Sun/OS, AIX, ULTRIX, HP-UX, AT&T SYSV */
  268.  
  269. #include    <setjmp.h>
  270.  
  271. #ifndef X_OK
  272. #define    R_OK    4    /* Test for Read permission */
  273. #define    W_OK    2    /* Test for Write permission */
  274. #define    X_OK    1    /* Test for eXecute permission */
  275. #endif  /* X_OK */
  276.  
  277. jmp_buf next;
  278.  
  279. void trynext()
  280. {
  281.     longjmp(next, 2);
  282. }
  283.  
  284.  
  285. int get_master_pty()
  286. {
  287.     int i, master_fd;
  288.     char *ptr;
  289.     struct stat statbuff;
  290. #ifdef PTYCHAR
  291.     static char ptychar[]=PTYCHAR;            /* X */ 
  292.     static char hexdigit[]=HEXDIGIT;        /* Y */
  293. #else
  294.     static char ptychar[]="pqrstuvwxyzPQRST";    /* X */ 
  295.     static char hexdigit[]="0123456789abcdef";    /* Y */
  296. #endif
  297.  
  298.     for (ptr=ptychar; *ptr != 0; ptr++)
  299.     {
  300.         strcpy(pty_name, "/dev/ptyXY");
  301.         pty_name[8]=(*ptr);  /* X */
  302.         pty_name[9]='0';   /* Y */
  303.  
  304.         if ( stat(pty_name, &statbuff) < 0 )
  305.             break;
  306. #ifdef OLDDEBUG
  307.         fprintf(stderr, "statted.\n");
  308. #endif
  309.         i=(-1);        /* Initialize i */
  310.  
  311.         /* Set a time limit for the open */
  312.         if ( setjmp(next) == -1 )
  313.             return(-1);
  314.         signal(SIGALRM, trynext);
  315.  
  316.         for ( ++i; hexdigit[i]; ++i)
  317.         {
  318.             pty_name[5]='p';
  319.             pty_name[9]=hexdigit[i];
  320.  
  321.             alarm(2);    /* Set an open timeout */
  322.  
  323.             if ( (master_fd=open(pty_name, O_RDWR)) >= 0 )
  324.             {
  325.                 alarm(0);     /* Reset the alarm */
  326.  
  327.                 pty_name[5]='t';
  328.                 sprintf(tty_name, "%s", pty_name);
  329. #ifdef OLDDEBUG
  330.                 fprintf(stderr, "tty: %s\n", tty_name);
  331. #endif
  332.                 if ( access(tty_name, R_OK|W_OK) == 0 ) {
  333.                     signal(SIGALRM, SIG_DFL);
  334.                     return (master_fd);
  335.                 } else {
  336.                     pty_name[5]='p';
  337.                     (void) close(master_fd);
  338.                 }
  339.             }
  340.             /* reset the alarm */
  341.             alarm(0);
  342.         }
  343.     }
  344.     return(-1);
  345. }
  346.  
  347.  
  348. /* Open the slave half of a pseudo-terminal. */
  349.  
  350. int get_slave_pty()
  351. {
  352.     int slave_fd;
  353.  
  354.     if ( (slave_fd=open(tty_name, O_RDWR)) < 0 )
  355.     {
  356.         close(master_fd);
  357.         return(-1);
  358.     }
  359.     return(slave_fd);
  360. }
  361.  
  362. #endif  /* if SOLARIS */
  363. #endif  /* if IRIX */
  364.  
  365.  
  366. /* These are the binary data functions that I am using instead of 
  367.    bcopy() and bzero(), written by Richard A. O'Keefe.
  368.      Thanks!
  369. */
  370.  
  371. void d_copy(src, dst, len)
  372.     register char *src, *dst;
  373.     register int len;
  374.     {
  375.     while (--len >= 0) *dst++ = *src++;
  376.     }
  377.  
  378. void d_zero(dst, len)
  379.     register char *dst;
  380.     register int len;
  381.     {
  382.     while (--len >= 0) *dst++ = 0;
  383.     }
  384.  
  385.  
  386.  
  387. /* Here are the Terminal manipulation routines...  */
  388.  
  389.  
  390. /* Code to disassociate from my tty. Yay! :) */
  391.  
  392. void dropctty()
  393. {
  394.     int fd;
  395.  
  396. #if defined(_POSIX_SOURCE) || defined(SOLARIS)
  397.     setsid();        /* The POSIX solution is simple. :) */
  398. #else
  399. #ifdef TIOCNOTTY  /* We want to get HP-UX, BSD, and Sun/OS here */
  400.     setpgrp(0, 0);
  401.  
  402. #ifndef CIBAUD   /* Sun/OS doesn't need to do TIOCNOTTY.  */
  403.     if ( (fd=open("/dev/tty", O_RDWR)) > (-1) ) 
  404.     {
  405.         if (ioctl(fd, TIOCNOTTY, 0) < 0)
  406.         {
  407.             perror("ioctl TIOCNOTTY error");
  408.             fprintf(stderr, "\r");
  409.         }
  410.         close(fd);
  411.     }
  412. #endif /* CIBAUD */
  413. #else /*  SYSV     */
  414.     setpgrp();
  415. #endif /* TIOCNOTTY */
  416. #endif /* _POSIX_SOURCE */
  417. }
  418.  
  419.  
  420. #ifdef HAVE_TERMIO_H
  421.  
  422. /* Get the modes of the controlling tty and save them.  Saves
  423.    ttymodes in tty_mode and returns -1 if ioctl fails. */
  424.  
  425. struct termio tty_mode;  /* Save tty mode here */
  426. static int tty_init=0;
  427.  
  428. int tty_getmode(fd)
  429. int fd;
  430. {
  431.     d_zero((char *)&tty_mode, sizeof(struct termio));
  432.     tty_init=1;    /* Flag: we have initialized the tty_mode struct */
  433.  
  434.     if ( ! isatty(fd) )
  435.         return(0);
  436.  
  437. #ifdef OLDDEBUG
  438.     fprintf(stderr, "Getting tty modes for tty_mode.\r\n");
  439. #endif
  440.  
  441.     if (ioctl(fd, TCGETA, (char *) &tty_mode) < 0)
  442.     {
  443. #ifdef DEBUG
  444.         perror("tty_getmode(): ioctl error");
  445. #endif
  446.         return(-1);  
  447.     }
  448.  
  449.     return(0);
  450. }
  451.  
  452.  
  453. /* Set a tty to a sane mode */
  454.  
  455. int tty_sane(fd)
  456. int fd;
  457. {
  458.     struct termio temp_mode;
  459.  
  460.     if ( ! isatty(fd) )
  461.         return(0);
  462.  
  463.     if ( ! tty_init )
  464.     {
  465.         if (ioctl(fd, TCGETA, (char *) &tty_mode) < 0)
  466.             return(-1);  
  467.     }
  468.  
  469. #ifdef SEVEN_BIT
  470.     temp_mode.c_iflag=(tty_mode.c_iflag|(BRKINT|IGNPAR|ISTRIP|ICRNL|IXON));
  471.     temp_mode.c_oflag=(tty_mode.c_oflag|(OPOST|ONLCR));
  472. #else
  473.     temp_mode.c_iflag=(tty_mode.c_iflag|(BRKINT|IGNPAR|ICRNL|IXON));
  474.     temp_mode.c_cflag=(tty_mode.c_cflag|(CS8|CREAD));
  475. #endif
  476.     temp_mode.c_lflag=(tty_mode.c_lflag|(ISIG|ICANON|ECHO|ECHOE|ECHOK));
  477.     temp_mode.c_cflag=(tty_mode.c_cflag|(CS7|PARENB|CREAD));
  478.     temp_mode.c_cc[VERASE]=('H'^64);
  479.     temp_mode.c_cc[VKILL]=('U'^64);
  480.     temp_mode.c_cc[VQUIT]=('\\'^64);
  481.     temp_mode.c_cc[VINTR]=('C'^64);
  482.     temp_mode.c_cc[VEOF]=('D'^64);
  483.     
  484.     /* TCSETAW is important for letting tty input drain. */
  485.     if ( ioctl(fd, TCSETAW, (char *)&temp_mode) < 0 )
  486.     {
  487. #ifdef DEBUG
  488.         perror("Can't set tty modes");
  489. #endif
  490.         return(-1);
  491.     }
  492.  
  493.     return(0);
  494. }
  495.  
  496.  
  497. /* Set a terminal in raw mode */
  498.  
  499. int tty_raw(fd)
  500. int fd;     /* of tty device */
  501. {
  502.     struct termio temp_mode;
  503.  
  504.     if ( ! tty_init )
  505.         return(-1);
  506.  
  507.     if ( ! isatty(fd) )
  508.         return(0);
  509.  
  510.     if ( ioctl(fd, TCGETA, (char *)&temp_mode) < 0 )
  511.         return(-1);
  512.  
  513. #ifdef SEVEN_BIT
  514.     temp_mode.c_iflag=(IGNBRK | ISTRIP);    /* turn off all input control */
  515. #else
  516.     temp_mode.c_iflag=(IGNBRK);        /* turn off all input control */
  517. #endif
  518.     temp_mode.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONLRET);
  519.                     /* disable output post-processing */
  520.     temp_mode.c_lflag = 0;
  521.     temp_mode.c_cc[VMIN]=1;        /* 1 or more chars satisfy read */
  522.     temp_mode.c_cc[VTIME]=0;    /* 10'ths of seconds between chars */
  523.  
  524.     /* TCSETAW is important for letting tty input drain. */
  525.     if (ioctl(fd, TCSETAW, (char *) &temp_mode) < 0)
  526.         return(-1);
  527.     return(0);
  528. }
  529.  
  530.  
  531. /* Restore terminal's mode to whatever it was on the most
  532.    recent call to the tty_getmode() function. */
  533.  
  534. int tty_reset(fd)
  535. int fd;
  536. {
  537.     if ( ! tty_init )
  538.         return(-1);
  539.  
  540.     if ( ! isatty(fd) )
  541.         return(0);
  542.  
  543.     /* TCSETAW is important for letting tty input drain. */
  544.     if (ioctl(fd, TCSETAW, (char *) &tty_mode) < 0)
  545.         return(-1);
  546.     return(0);
  547. }
  548.  
  549. #else  /* no /usr/include/termio.h */
  550. #ifdef NEED_COMPAT_H        /* FreeBSD needs this */
  551. #include <sys/ioctl_compat.h>
  552. #endif /* NEED_COMPAT_H */
  553.  
  554. /* Set a tty to a sane mode */
  555.  
  556. int tty_sane(fd)
  557. int fd;
  558. {
  559.     struct sgttyb temp_mode;
  560.  
  561.     if ( ! isatty(fd) )
  562.         return(0);
  563.  
  564.     if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0)
  565.         return(-1);
  566.  
  567.     temp_mode.sg_flags|=ECHO;
  568.     
  569.     if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
  570.         return(-1);
  571.  
  572.     return(0);
  573. }
  574.  
  575.  
  576.  
  577. /* Get the modes of the controlling tty and save them.  Saves
  578.    ttymodes in tty_mode and returns 1 if ioctl fails. */
  579.  
  580. static struct sgttyb    tty_mode;    /* save tty mode here */
  581.  
  582. int tty_getmode(fd)
  583. int fd;
  584. {
  585.     if ( ! isatty(fd) )
  586.         return(0);
  587.  
  588.     if (ioctl(fd, TIOCGETP, (char *) &tty_mode) < 0)
  589.         return(-1);
  590.  
  591.     return(0);
  592. }
  593.  
  594. /*
  595.  * Put a terminal device into RAW mode with ECHO off.
  596.  * Before doing so we first save the terminal's current mode,
  597.  * assuming the caller will call the tty_reset() function
  598.  * (also in this file) when it's done with raw mode.
  599.  */
  600.  
  601. int tty_raw(fd)
  602. int    fd;        /* of terminal device */
  603. {
  604.     struct sgttyb    temp_mode;
  605.  
  606.     if ( ! isatty(fd) )
  607.         return(0);
  608.  
  609.     temp_mode = tty_mode;
  610.  
  611.     temp_mode.sg_flags |= RAW;    /* turn RAW mode on */
  612.     temp_mode.sg_flags &= ~ECHO;    /* turn ECHO off */
  613.     if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
  614.         return(-1);
  615.  
  616.     return(0);
  617. }
  618.  
  619. /*
  620.  * Restore a terminal's mode to whatever it was on the most
  621.  * recent call to the tty_getmode() function above.
  622.  */
  623.  
  624. int tty_reset(fd)
  625. int    fd;        /* of terminal device */
  626. {
  627.     if ( ! isatty(fd) )
  628.         return(0);
  629.  
  630.     if (ioctl(fd, TIOCSETP, (char *) &tty_mode) < 0)
  631.         return(-1);
  632.  
  633.     return(0);
  634. }
  635. #endif /* HAVE_TERMIO_H */
  636.  
  637.  
  638. /* Set the pty window size to the size of the virtual window */
  639.  
  640. #ifdef TIOCSWINSZ
  641.  
  642. static struct /* winsize */ {
  643.         unsigned short    ws_row;        /* rows, in characters */
  644.         unsigned short    ws_col;        /* columns, in characters */
  645.         unsigned short    ws_xpixel;    /* horizontal size - not used */
  646.         unsigned short    ws_ypixel;    /* vertical size - not used */
  647.     } mywinz;
  648.  
  649. void pty_setwin(fd, win)
  650. int fd;            /* The pty file descriptor */
  651. int win;        /* 0 for upper, 1 for lower window */
  652. {
  653.     if ( win == UPPER )
  654.         mywinz.ws_row=WU_lines;
  655.     else
  656.         mywinz.ws_row=WL_lines;
  657.     mywinz.ws_col=W_columns;
  658.     mywinz.ws_xpixel=0;
  659.     mywinz.ws_ypixel=0;
  660.     (void) ioctl(fd, TIOCSWINSZ, &mywinz);
  661. }
  662.  
  663. #else
  664. void pty_setwin(fd, win)
  665. int fd;
  666. int win;
  667. {
  668.     /* Bogus routine */
  669. }
  670. #endif /* TIOCSWINSZ */
  671.  
  672. /*
  673.  * Write "n" bytes to a descriptor.
  674.  * Use in place of write() when fd is a stream socket.
  675.  */
  676.  
  677. int writen(fd, ptr, nbytes)
  678. register int    fd;
  679. register char    *ptr;
  680. register int    nbytes;
  681. {
  682.     int    nleft, nwritten;
  683.  
  684.     nleft = nbytes;
  685.     while (nleft > 0) {
  686.         nwritten = write(fd, ptr, nleft);
  687.         if (nwritten <= 0)
  688.             return(nwritten);        /* error */
  689.  
  690.         nleft -= nwritten;
  691.         ptr   += nwritten;
  692.     }
  693.     return(nbytes - nleft);
  694. }
  695.  
  696.  
  697. /* 
  698.    A function to put strings in the environment using malloc(). 
  699.    Returns a pointer to the environment string or NULL if malloc() fails.
  700.  */
  701.  
  702. char *myputenv(string)
  703. char *string;
  704. {
  705.     extern char **environ;    /* The process environment strings */
  706.  
  707.     char *newptr, **envptr;
  708.     char *tmptr, temp[BUFSIZ];
  709.     int   distance, n=0;
  710.  
  711.     for ( distance=0; ((*(string+distance)) && 
  712.                   ((*(string+distance)) != '=')); ++distance );
  713.     if ( ! (*(string+distance)) )
  714.         return(NULL);
  715.     else
  716.         ++distance;
  717.                                 
  718.     if ( (newptr=(char *)malloc(strlen(string)+1)) == NULL )
  719.         return(NULL);
  720.     else
  721.         strcpy(newptr, string);
  722.  
  723.     for ( envptr=environ; *envptr; ++envptr, ++n ) {
  724.         if ( strncmp(*envptr, string, distance) == 0 ) {
  725.             *envptr=newptr;
  726.             return(newptr);
  727.         }
  728.     }
  729.  
  730.     *envptr=newptr;
  731.     ++envptr;
  732.     *envptr=NULL;
  733.     
  734.     return(newptr);
  735. }
  736.  
  737.  
  738. /* * * * * * * Routines to parse a line into an array of tokens * * * * * * */
  739.  
  740. static int istoken(c, tokens)
  741. char c;
  742. char *tokens;
  743. {
  744.     while ( *tokens ) {
  745.         if ( c == *(tokens++) )
  746.             return(1);
  747.     }
  748.     return(0);
  749. }
  750.  
  751. /* This version of tokenize is destructive to the line it parses. */
  752.  
  753. void tokenize(array, line, tokens)
  754. char *array[];
  755. char *line;
  756. char *tokens;
  757. {
  758.     char *head, *ptr;
  759.     int i=0;
  760.  
  761.     for ( head=line; *line; ) {
  762.         if ( istoken(*line, tokens) ) {
  763.             *(line++)='\0';
  764.             array[i++]=head;
  765.             while ( istoken(*line, tokens) )
  766.                 ++line;
  767.             head=line;
  768.         } else
  769.             ++line;
  770.     }
  771.     array[i++]=head;
  772.     array[i]=NULL;
  773. }
  774.  
  775. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 
  776.  
  777.